#include "gtest/gtest.h"
#include "DataStructure/Common/Constant.h"
#include "../../IntegrationFormula/Gauss2D2X2P.h"
#include "../Plane4NodeShpFunc.h"

using SG::DataStructure::Common::TOLERANCE;
using SG::Algebra::Matrixd;
using SG::FEMSolver::Element::Plane4NodeShpFunc;

// 形函数在本点为1，它点为0
TEST (Plane4NodeShpFuncTest, shpFuncTest)
{
    // Input
    SG::DataStructure::FEM::IntegPointArray integs (4);
    integs[0].m_x = -1.0; integs[0].m_y = -1.0;
    integs[1].m_x =  1.0; integs[1].m_y = -1.0;
    integs[2].m_x =  1.0; integs[2].m_y =  1.0;
    integs[3].m_x = -1.0; integs[3].m_y =  1.0;
    
    // Test data
    auto shpfunc = Plane4NodeShpFunc ();
    shpfunc.Compute (integs);

    // 测试 1号节点处形函数
    auto& m1 = shpfunc.GetShapeFunction (0);
    ASSERT_NEAR (m1 (0, 0), 1.0, TOLERANCE);
    ASSERT_NEAR (m1 (1, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m1 (2, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m1 (3, 0), 0.0, TOLERANCE);

    // 测试 2号节点处形函数
    auto& m2 = shpfunc.GetShapeFunction (1);
    ASSERT_NEAR (m2 (0, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m2 (1, 0), 1.0, TOLERANCE);
    ASSERT_NEAR (m2 (2, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m2 (3, 0), 0.0, TOLERANCE);

    // 测试 3号节点处形函数
    auto& m3 = shpfunc.GetShapeFunction (2);
    ASSERT_NEAR (m3 (0, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m3 (1, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m3 (2, 0), 1.0, TOLERANCE);
    ASSERT_NEAR (m3 (3, 0), 0.0, TOLERANCE);

    // 测试 4号节点处形函数
    auto& m4 = shpfunc.GetShapeFunction (3);
    ASSERT_NEAR (m4 (0, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m4 (1, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m4 (2, 0), 0.0, TOLERANCE);
    ASSERT_NEAR (m4 (3, 0), 1.0, TOLERANCE);
}

// 标准母元， jocobian为单位矩阵
TEST (Plane4NodeShpFuncTest, shpFuncDerivativeTest)
{
    // Input
    SG::FEMSolver::Element::Gauss2D2X2P integCalc;
    auto integs = integCalc.GetPoints ();
    Matrixd nodes (4, 2);
    nodes (0, 0) = -1.0; nodes (0, 1) = -1.0;
    nodes (1, 0) =  1.0; nodes (1, 1) = -1.0;
    nodes (2, 0) =  1.0; nodes (2, 1) =  1.0;
    nodes (3, 0) = -1.0; nodes (3, 1) =  1.0;
    
    // Target data
    auto I = SG::Algebra::identity (2);

    // Test data
    auto shpfunc = Plane4NodeShpFunc ();
    shpfunc.Compute (integs);

    // 测试 1号积分点形函数导数
    auto I1 = shpfunc.GetShapeFunctionDerivative (0) * nodes;
    ASSERT_TRUE (I1 == I);

    // 测试 2号积分点处形函数导数
    I1 = shpfunc.GetShapeFunctionDerivative (1) * nodes;
    ASSERT_TRUE (I1 == I);

    // 测试 3号积分点处形函数导数
    I1 = shpfunc.GetShapeFunctionDerivative (2) * nodes;
    ASSERT_TRUE (I1 == I);

    // 测试 4号积分点处形函数导数
    I1 = shpfunc.GetShapeFunctionDerivative (3) * nodes;
    ASSERT_TRUE (I1 == I);
}